/**
 * Copyright (c) 2014 by it's authors. 
 * All rights reserved. See COPYING, AUTHORS.
 * 
 * This file is part of DanceMania project; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License, Version 3.
 * 
 * DanceMania is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License,
 * along with this program. If not, see http://www.gnu.org/licenses/.
 */
package com.m2dl.niptus.pathtrack.classes;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import com.m2dl.niptus.pathtrack.MainActivity;
import com.m2dl.niptus.pathtrack.R;
import com.m2dl.niptus.pathtrack.db.DBAdapter;
import com.m2dl.niptus.pathtrack.db.Location;
import com.m2dl.niptus.pathtrack.utils.Constants;

public class CompassView extends View implements SensorEventListener {
	private final String TAG = Constants.TAG + "." + getClass().getSimpleName();

	private Bitmap mCompass;
	private Matrix mCompassMatrix;
	private boolean mResized = false;
	private float mAngle = 0f;

	private SensorManager mSensorManager;

	/** Sensor data **/
	private float[] mGravity;
	private float[] mGeomagnetic;
	
	private MainActivity mMainActivity;

	public CompassView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context);
	}

	public CompassView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context);
	}

	public CompassView(Context context) {
		super(context);
		init(context);
	}

	private void init(Context context) {
		Log.i(TAG, "Compass initialized");
		
		// Define bitmap of position circle
		mCompass = BitmapFactory.decodeResource(getResources(), R.drawable.compass);
		mCompassMatrix = new Matrix();

		// Define accelerometer variables
		mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
	}
	
	public void setParent(MainActivity activity) {
		this.mMainActivity = activity;
	}

	@Override
	public void onDraw(Canvas canvas) {
		if (!mResized) {
			mCompass = Bitmap.createScaledBitmap(mCompass, getWidth() / 5, getWidth() / 5, true);
			mResized = true;
		}

		canvas.drawBitmap(mCompass, mCompassMatrix, null);
	}

	@Override
	public void onSensorChanged(SensorEvent se) {
		if (se.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
			mGravity = se.values;
			processSensorData();
		}

		if (se.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
			mGeomagnetic = se.values;
			processSensorData();
		}
	}

	public void onAccuracyChanged(Sensor sensor, int accuracy) {
	}

	public void processSensorData() {
		if (mGravity != null && mGeomagnetic != null) {
			float R[] = new float[9];
			float I[] = new float[9];
			boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);
			if (success) {
				float orientation[] = new float[3];
				SensorManager.getOrientation(R, orientation);
				float newAngle = (float) ((-orientation[0] * 360f) / (2 * Math.PI)); // Azimuth
				
				if (Math.abs((double) newAngle - mAngle) > 10)
					showDirections();
				
				mAngle = newAngle;

				Matrix m = new Matrix();
				m.postRotate(mAngle, mCompass.getWidth() / 2, mCompass.getHeight() / 2);
				mCompassMatrix.set(m);
				invalidate();
			}

			// Reset data
			mGravity = null;
			mGeomagnetic = null;
		}
	}

	/**
	 * Callback for the activity owning the view to attach sensors
	 */
	public void attachSensors() {
		mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
		mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_NORMAL);
	}

	/**
	 * Callback for the activity owning the view to detach sensors
	 */
	public void detachSensors() {
		mSensorManager.unregisterListener(this);
	}

	/** Path section **/
	class PathComparator implements Comparator<Location> {
	    @Override
	    public int compare(Location a, Location b) {
	        if (a.getId() < b.getId())
	        	return -1;
	        else if (a.getId() > b.getId())
	        	return 1;
	        else
	        	return 0;
	    }
	}
	
	public void showDirections() {
		DBAdapter db = new DBAdapter(getContext());
		List<Location> path = db.getAllObjects();
		db.close();
		
		if (path.size() < 5)
			return;
		
		Collections.sort(path, new PathComparator());
		
		Location home = path.get(0);
		Location current = path.get(path.size() - 1);
		
		double correctAngle = Math.atan2(Math.abs(home.getY() - current.getY()),
				Math.abs(home.getX() - current.getX()));
		
		correctAngle = (correctAngle * 180) / Math.PI;
		double orienAngle = (mAngle > 0 ? 180 - mAngle : 180 + mAngle);
		
		double dif = correctAngle - orienAngle;
		if (dif >= -45 && dif < 45)
			mMainActivity.showArrow(1);
		else if (dif < 135 && dif >= 45)
			mMainActivity.showArrow(0);
		else if ((dif > 135 && dif <= 180) || (dif > -180 && dif <= -135))
			mMainActivity.showArrow(3);
		else
			mMainActivity.showArrow(2);
		
		double distance = (home.getX() - current.getX()) * (home.getX() - current.getX()) + (home.getY() - current.getY()) * (home.getY() - current.getY()); 
		if (Math.sqrt(distance) < 50)
			mMainActivity.destinationReached();
	}
	
}